// Grammar.cpp: implementation of the Grammar class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "Grammar.h"
#include <iostream>

using namespace std;

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

Grammar::Grammar()
{
	tempNum=0;
	ifJump=1;
	ifTisFirst=1;
	ifEisFirst=1;
}

Grammar::~Grammar()
{

}

void Grammar::addProduction(string var, string f)
{
	Production temp(var,f);
	GrammarList.push_back(temp);
	//cout<<temp.getVariable()<<"->"<<temp.getFormula()<<endl;

	list<string>::iterator p=VariableList.begin();
	while (p!=VariableList.end())
	{
		if (*p==var)
		{
			break;
		}
		p++;
	}
	if (p==VariableList.end())
	{
		VariableList.push_back(var);
		//cout<<var<<endl;
	}
}

char* Grammar::X(char* ch)
{	Lexical lex;
	tempS.next=0;
	tempS.isLoop=true;
	ifJump=1;

	if ((ch=S(ch))!=NULL)
	{
		//cout<<tempS.code<<endl;
		//cout<<"S;"<<endl;
		
		wordnode terminal=lex.WordPickup(&ch);
		if(terminal.word==";")
		{
			
			if (ifJump!=0)
			{
				char str[10];
				tempX.code.append(tempS.code);
				tempX.code.append("\nL0");
				//tempX.code.append(itoa(tempS.next,str,10));
				tempX.code.append(":");
			}
			else
			{
				tempX.code.append(tempS.code);
			}
			cout<<tempX.code<<endl;
			return ch;
		}
		else
			return NULL;
	}
	else
		return NULL;
		
}

char* Grammar::S(char* ch)
{
	Lexical lex;
	att_S ss;
	char a[10];
	wordnode terminal=lex.WordPickup(&ch);
	if (terminal.word=="while")
	{
		int templabel=tempS.begin;
		//cout<<templabel<<endl;
		tempS.begin=newlabel();
		if(tempS.isLoop)
			tempS.next=tempS.begin-1;
		tempS.isLoop=true;
		//if (ch)
		//{
			//if (tempS.begin>1)
			//{
			//	ifJump--;
			//	tempS.begin=templabel;
			//}
		//}
		tempC.isTrue=tempS.begin+1;
		ss.begin=tempC.isTrue;
		tempC.isFalse=tempS.next;
		ss.next=tempS.begin;
		if ((ch=C(ch))!=NULL)
		{
			//cout<<tempC.code<<endl;
			//cout<<tempS.begin<<endl;
			
				tempS.code.append("L");
				
				tempS.code.append(itoa(tempS.begin,a,10));
				tempS.code.append(":\n");
				tempS.code.append(tempC.code);
				//tempS.code.append("L");
				//tempS.code.append(itoa(tempC.isTrue,a,10));
				//tempS.code.append(":\n");
				//tempS.code.append(ss.code);
				//tempS.code.append(" goto L");
				//tempS.code.append(itoa(tempS.begin,a,10));
				//tempS.code.append("\n");
			
				//tempS.code.append(tempC.code);
				//tempS.code.append("L");
				//tempS.code.append(itoa(tempC.isTrue,a,10));
				//tempS.code.append(":\n");
				//tempS.code.append(ss.code);
				//tempS.code.append(" goto L");
				//tempS.code.append(itoa(tempS.begin,a,10));
				//tempS.code.append("\n");
			
			terminal=lex.WordPickup(&ch);
			if (terminal.word=="do")
			{
				if((ch=S(ch))!=NULL)
				{
/*					if (tempS.begin==1)
					{
						//tempS.code.append("L");
						
						//tempS.code.append(itoa(tempS.begin,a,10));
					//	tempS.code.append(":\n");
						//tempS.code.append(tempC.code);
						tempS.code.append("L");
						tempS.code.append(itoa(tempC.isTrue,a,10));
						tempS.code.append(":\n");
						tempS.code.append(ss.code);
						tempS.code.append(" goto L");
						tempS.code.append(itoa(tempS.begin,a,10));
						tempS.code.append("\n");
				}
					else
					{
						//tempS.code.append(tempC.code);
						tempS.code.append("L");
						tempS.code.append(itoa(tempC.isTrue,a,10));
						tempS.code.append(":\n");
						tempS.code.append(ss.code);
						tempS.code.append(" goto L");
						tempS.code.append(itoa(tempS.begin,a,10));
						tempS.code.append("\n");
					}
					//cout<<tempS.code<<endl;
					//cout<<"while C do S "<<endl;
*/					return ch;
				}
			}
			else
				return NULL;
		}
		else
			return NULL;
	}
	else if (terminal.word=="if")
	{
		tempS.begin=newlabel();
		tempC.isTrue=tempS.begin+1;
		if(tempS.isLoop)
			tempS.next=tempS.begin-1;
		tempS.isLoop=false;
		tempS1.begin=tempS.next;
		tempC.isFalse=tempS1.begin;
		ss.next=tempS1.begin;
		tempS1.next=ss.next;
		if ((ch=C(ch))!=NULL)
		{
			tempS.code.append("L");
			char s[10];
			tempS.code.append(itoa(tempS.begin,s,10));
			tempS.code.append(":\n");
			tempS.code.append(tempC.code);
			//cout<<tempC.code<<endl;
			terminal=lex.WordPickup(&ch);
			if (terminal.word=="then")
			{
				if ((ch=S(ch))!=NULL)
				{
					if ((ch=S1(ch))!=NULL)
					{
						if (tempS1.isElse)
						{
							tempS.next=tempS1.next;
						}
						
						//tempS.code.append(":\n");
						//tempS.code.append(ss.code);
						//tempS.code.append(tempS1.code);
						//cout<<"if C then S S'"<<endl;
						return ch;
					}
					else
						return NULL;
				}
				else
					return NULL;
			}
			else
				return NULL;
		}
		else
			return NULL;
	}
	else if (terminal.attribute=="id")
	{
		string vName=terminal.word;
		terminal=lex.WordPickup(&ch);
		tempS.begin=newlabel();
		if(tempS.isLoop)
			tempS.next=tempS.begin-1;
		tempS.isLoop=false;
		if (terminal.word=="=")
		{
			if ((ch=E(ch))!=NULL)
			{
				//cout<<tempE.code<<endl;
				tempS.code.append("L");
				char s[10];
				tempS.code.append(itoa(tempS.begin,s,10));
				tempS.code.append(":\n");
				tempS.code.append(" ");
				tempS.code.append(tempE.code);
				tempS.code.append(vName);
				tempS.code.append("=");
				tempS.code.append(tempE.place);
				tempS.code.append("\n");
				tempS.code.append(" goto L");
				tempS.code.append(itoa(tempS.next,s,10));
				//cout<<"id=E"<<endl;
				//cout<<tempS.code<<endl;
				return ch;
			}
			else
				return NULL;
		}
		else
			return NULL;					
	}
	else
		return NULL;
}

char* Grammar::S1(char* ch)
{	Lexical lex;
	char* temp=ch;
	wordnode terminal=lex.WordPickup(&ch);
	if (terminal.word=="else")
	{
		tempS1.next=newlabel();
		tempS.next=tempS1.next;
		tempS.begin=tempS1.begin;
		if ((ch=S(ch))!=NULL)
		{
			tempS1.code="goto L";
			char s[10];
			tempS1.code.append(itoa(tempS1.next,s,10));
			tempS1.code.append(":\n");
			tempS1.code.append(tempS.code);
			tempS1.code.append("\n");
			//cout<<"else S"<<endl;
			return ch;
		}
		else
			return NULL;
	}
	else
	{
		tempS1.next=tempS1.begin;
		tempS1.code="";
		tempS1.isElse=true;
		//cout<<"null"<<endl;
		return temp;
	}
}

char* Grammar::C(char* ch)
{
	Lexical lex;
	if ((ch=E(ch))!=NULL)
	{
		att_E EE=tempE;
		if ((ch=C1(ch))!=NULL)
		{
			//cout<<EE.code<<endl;
			tempC.code=EE.code;
			tempC.code.append(tempC1.code);
			if(!tempC.code.empty())
				tempC.code.append("\n");
			tempC.code.append(" if ");
			tempC.code.append(EE.place);
			tempC.code.append(tempC1.place);
			tempC.code.append(tempE.place);
			tempC.code.append(" goto L");
			char a[10];
			tempC.code.append(itoa(tempC.isTrue,a,10));
			tempC.code.append("\n goto L");
			tempC.code.append(itoa(tempC.isFalse,a,10));
			tempC.code.append("\n");

			//cout<<tempC.code<<endl;
			//cout<<"E C'"<<endl;
			return ch;
		}
		else
			return NULL;
	}
	else
		return NULL;
}

char* Grammar::C1(char* ch)
{
	Lexical lex;
	
	wordnode terminal=lex.WordPickup(&ch);
	if (terminal.word==">"||terminal.word=="<"||terminal.word=="=")
	{
		if ((ch=E(ch))!=NULL)
		{
			tempC1.place=terminal.word;
			tempC1.code=tempE.code;
			//cout<<tempC1.code<<endl;
			//cout<<terminal.word<<"E"<<endl;
			return ch;
		}
		else 
			return NULL;
	}
	else
		return NULL;
}

char* Grammar::E(char* ch)
{
	Lexical lex;
	if ((ch=T(ch))!=NULL)
	{
		
		if ((ch=E1(ch))!=NULL)
		{	
			//cout<<tempT.code<<endl;
			//cout<<tempE.code<<endl;
			//cout<<"T E'"<<endl;
			return ch;
		}
		else
			return NULL;
	}
	else
		return NULL;
}

char* Grammar::E1(char* ch)
{
	Lexical lex;
	char* temp=ch;
	wordnode terminal=lex.WordPickup(&ch);
	att_T TT=tempT;
	//cout<<tempT.place<<endl;
	if (terminal.word=="+"||terminal.word=="-")
	{
		
		tempE1.place=terminal.word;
		
		if ((ch=T(ch))!=NULL)
		{	//cout<<tempT.place<<endl;
			if(ifEisFirst==1)
			{
				tempE.place=newtemp();
				tempE.code=TT.code;
				tempE.code.append(tempT.code);
				tempE.code.append(" ");
				tempE.code.append(tempE.place);
				tempE.code.append("=");
				tempE.code.append(TT.place);
				tempE.code.append(tempE1.place);
				tempE.code.append(tempT.place);
			}
			else
			{
			}
			ifEisFirst=0;
			//cout<<tempE.code<<endl;
			if ((ch=E1(ch))!=NULL)
			{
				//cout<<terminal.word<<"TE'"<<endl;
				return ch;
			}
			else
				return NULL;
		}
		else 
			return NULL;
	}
	else
	{
		tempE1.place="";
		//tempE.code=TT.code;
		if(ifEisFirst==1)
		{
			//cout<<"55"<<endl;
			tempE.place=TT.place;
			tempE.code=TT.code;
		}
		//tempE1.code="";
		//cout<<"null"<<endl;
		ifEisFirst=1;
		return temp;
	}
}

char* Grammar::T(char* ch)
{
	Lexical lex;
	if ((ch=F(ch))!=NULL)
	{
		
		if ((ch=T1(ch))!=NULL)
		{
			//cout<<tempT.code<<endl;	
			//cout<<"FT'"<<endl;
			return ch;
		}
		else
			return NULL;
	}
	else
		return NULL;
}

char* Grammar::T1(char* ch)
{
	Lexical lex;
	char* temp=ch;
	wordnode terminal=lex.WordPickup(&ch);
	att_F FF=tempF;
	//cout<<FF.code<<endl;
	if (terminal.word=="*"||terminal.word=="/")
	{
		tempT1.place=terminal.word;
		
		if ((ch=F(ch))!=NULL)
		{
			if(ifTisFirst==1)
			{
				tempT.place=newtemp();
				tempT.code=FF.code;
				tempT.code.append(tempF.code);
				tempT.code.append(" ");
				tempT.code.append(tempT.place);
				tempT.code.append("=");
				tempT.code.append(FF.place);
				tempT.code.append(tempT1.place);
				tempT.code.append(tempF.place);
				tempT.code.append("\n");
			}
			else
			{
				string ts=tempT.place;
				tempT.place=newtemp();
				//tempT.code.append(FF.code);
				//tempT.code.append(tempF.code);
				tempT.code.append(" ");
				tempT.code.append(tempT.place);
				tempT.code.append("=");
				tempT.code.append(ts);
				tempT.code.append(tempT1.place);
				tempT.code.append(tempF.place);
				tempT.code.append("\n");
			}
			//cout<<tempT.code<<endl;

			ifTisFirst=0;
			if ((ch=T1(ch))!=NULL)
			{
				//cout<<tempT.code<<endl;
				//cout<<terminal.word<<"FT'"<<endl;
				return ch;
			}
			else
				return NULL;
		}
		else 
			return NULL;
	}
	else
	{
		//tempT.code=FF.code;
		if(ifTisFirst==1){
			tempT.place=FF.place;
			tempT.code=FF.code;
		}
		tempT1.place="";
		//tempT1.code="";
		//cout<<"null"<<endl;
		ifTisFirst=1;
		return temp;
	}
}

char* Grammar::F(char* ch)
{
	Lexical lex;
	wordnode terminal=lex.WordPickup(&ch);
	if (terminal.word=="(")
	{
		if ((ch=E(ch))!=NULL)
		{
			wordnode terminal=lex.WordPickup(&ch);
			if (terminal.word==")")
			{
				tempF.place=tempE.place;
				tempF.code=tempE.code;
				//cout<<tempE.code<<endl;
				//cout<<"(E)"<<endl;
				return ch;
			}
			else
				return NULL;
		}
		else
			return NULL;
	}
	else if (terminal.attribute=="id"||terminal.attribute=="int8"||terminal.attribute=="int10"||terminal.attribute=="int16")
	{
		tempF.place=terminal.word;
		//cout<<tempF.place<<endl;
		tempF.code="";
		//cout<<terminal.attribute<<endl;
		return ch;
	}
	else
		return NULL;
}

int Grammar::newlabel()
{
	return ifJump++;
}

string Grammar::newtemp()
{
	tempNum++;
	string s="t";
	char a[10];
	s.append(itoa(tempNum,a,10));
	return s;
}

void Grammar::clear()
{

}
